#pragma once

#include <iostream>
#include <string>
#include <unordered_map>
#include "Connection.hpp"
#include "Epoller.hpp"

using namespace log_ns;

// 类似一个容器，核心工作：
// 1、管理 connection 和对应的内核事件
// 2、事件派发

class Reactor
{
private:
    const static int num = 64;

public:
    Reactor()
        : _epoller(std::make_unique<Epoller>()), _isrunning(false)
    {
    }

    void AddConnection(int fd, uint32_t events, const InetAddr& addr, int type)
    {
        // 1、构建一个 Connection 对象
        Connection *conn = new Connection(fd);
        conn->SetEvents(events);
        conn->SetConnectionType(type);
        conn->SetAddr(addr);
        
        // 将当前对象设置进入所有的 Connection 中 
        conn->SetReactor(this);

        // 对该连接的处理方式
        if (conn->GetConnectionType() == ListenConnection)
        {
            conn->RegisterHandler(_OnNewConnection, nullptr, nullptr);
        }
        else
        {
            conn->RegisterHandler(_OnRecver, _OnSender, _OnExcepter);
        }

        // 2、fd 和 events 写入内核中，托管给 epoll
        if (!_epoller->AddEvent(conn->GetSockfd(), conn->GetEvents()))
            return;

        // 3、托管给 _connections
        _connections.insert({fd, conn});
    }

    void EnableConnectionReadWrite(int sockfd, bool readable, bool writeable)
    {
        if (!IsConnectionExists(sockfd))
        {
            return;
        }
        uint32_t events = (readable ? EPOLLIN : 0) | (writeable ? EPOLLOUT : 0) | EPOLLET;
        _connections[sockfd]->SetEvents(events);

        // 写透进内核中 
        _epoller->ModEvent(_connections[sockfd]->GetSockfd(), _connections[sockfd]->GetEvents());
    }

    void DelConnection(int sockfd)
    {
        // 安全检测
        if (!IsConnectionExists(sockfd)) return;
        int tempfd = sockfd;
        // 在内核中移除对 sockfd 
        EnableConnectionReadWrite(sockfd, false, false);
        _epoller->DelEvent(sockfd);
        // 关闭 sockfd 
        _connections[sockfd]->Closefd();
        // 在 Reactor 中移除对 Connection 的关心
        delete _connections[sockfd];
        _connections.erase(sockfd);
        LOG(INFO, "sockfd %d quit successfully!\n", tempfd);
    }

    void LoopOnce(int timeout)
    {
        int n = _epoller->Wait(revs, num, timeout);
        for (int i = 0; i < n; ++i)
        {
            int sockfd = revs[i].data.fd;
            uint32_t revents = revs[i].events;
            // 利用读写统一处理异常状态
            if (revents & EPOLLERR)
                revents |= (EPOLLIN | EPOLLOUT);
            if (revents & EPOLLHUP)
                revents |= (EPOLLIN | EPOLLOUT);

            if (revents & EPOLLIN)
            {
                if (IsConnectionExists(sockfd) && _connections[sockfd]->HandlerRecver())
                {
                    // 把读事件就绪派发给对应的 connection
                    _connections[sockfd]->HandlerRecver()(_connections[sockfd]);
                }
            }
            if (revents & EPOLLOUT)
            {
                if (IsConnectionExists(sockfd) && _connections[sockfd]->HandlerSender())
                {
                    // 把写事件就绪派发给对应的 connection
                    _connections[sockfd]->HandlerSender()(_connections[sockfd]);
                }
            }
        }
    }

    void Dispatcher() // 事件派发
    {
        int timeout = -1;
        _isrunning = true;
        while (_isrunning)
        {
            LoopOnce(timeout);
            PrintDebug();
        }
        _isrunning = false;
    }

    bool IsConnectionExists(int sockfd)
    {
        return _connections.find(sockfd) != _connections.end();
    }

    void SetOnNewConnection(handler_t OnNewConnection)
    {
        _OnNewConnection = OnNewConnection;
    }

    void SetOnNormalHandler(handler_t OnRecver, handler_t OnSender, handler_t OnExcepter)
    {
        _OnRecver = OnRecver;
        _OnSender = OnSender;
        _OnExcepter = OnExcepter;
    }

    void PrintDebug()
    {
        std::string fdlist;
        for (auto& conn : _connections)
        {
            fdlist += std::to_string(conn.second->GetSockfd()) + " ";
        }
        LOG(DEBUG, "List managed by epoll: %s\n", fdlist.c_str());
    }

    ~Reactor()
    {
    }

private:
    std::unordered_map<int, Connection *> _connections;
    std::unique_ptr<Multiplex> _epoller;
    bool _isrunning;

    struct epoll_event revs[num];

    // 添加处理 socket 的方法集
    // 处理新连接 
    handler_t _OnNewConnection;
    // 处理 IO 
    handler_t _OnRecver;
    handler_t _OnSender;
    handler_t _OnExcepter;
};
